/*
 * 
 */
package com.javaking.clanteam.hvz.sql;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;

import android.util.Log;

/**
 * This class is to be used as a relay between this app and our SQL server.
 *
 * @author Scott
 */
public class SQLRelay {
	
	/**
	 * An enum to tell which mode we will be querying the server in.
	 */
	public enum QueryMode
	{
		READ, ADD_USER, REMOVE_USER, MODIFY_INFO, KILL,
		RESURRECT, KILLCODE_ASSIGN, KILLCODE_ACQUIRE,
		EXECUTE_SQL
	}
	
	/**
	 * Query the SQL server.
	 *
	 * @param mode What mode we will be querying the server in.
	 * @param params All paramaters other than the mode
	 * @return The response from our server.
	 * @deprecated Use one of the provided methods instead
	 */
	public static Object queryServer(QueryMode mode, List<NameValuePair> params)
	{
		String result = null;
		InputStream in = null;
		
		// generate the URL
		StringBuilder sb = new StringBuilder("http://javaking.clanteam.com/hvz/hvz_mysql.php?");
		sb.append("mode="+mode.toString());
		
		// Get all the params and add them to the string
		for (Iterator<NameValuePair> i = params.iterator(); i.hasNext();) {
			NameValuePair pair = i.next();
			sb.append('&'+pair.getName()+'='+pair.getValue());
		}
		String urlString = sb.toString();
		
		// open the connection
		try
		{
			// Must make the url 'friendly' and form the connection.
			URL url = new URL(urlString.replaceAll(" ", "%20"));
    		URLConnection connection = url.openConnection();
    		connection.connect();
    		in = connection.getInputStream();
		} catch (Exception e) {
			Log.e("Humans VS Zombies", "Error in http connection "+e.toString());
    		return null;
		}
		
		// Read the query result and store to a string.
    	try
    	{
    		if (in==null)
    		{
    			Log.e("Humans VS Zombies", "Something failed in the http try-catch and a failure passed.");
    			return null;
    		}
    		
    		// Get a reader from the input stream
    		BufferedReader reader = new BufferedReader(new InputStreamReader(in));
    		
    		// Clear the string buffer.
    		sb.delete(0, sb.length());
    		
    		// Store the returned info into a string.
    		String line = null;
    		while ((line=reader.readLine())!=null)
    		{
    			sb.append(line + "\n");
    		}
    		in.close();
    		reader.close();
    		
    		result = sb.toString();
    	} catch (Exception e) {
    		Log.e("Humans VS Zombies", "Error converting result "+e.toString());
    		return null;
    	}
    	
    	// Convert the string into a JSON object.
    	try
    	{    		
    		// Get the first JSON "object" (may be a JSON Array or JSON Object).
    		JSONTokener tokener = new JSONTokener(result);
    		return tokener.nextValue();
//    		return new JSONObject(result);
    	} catch (JSONException e) {
    		Log.e("Humans VS Zombies", "Error parsing JSON "+e.toString());
    		return null;
    	}
	}
	
 	/**
	  * Read users based off all the given params.
	  *
	  * @param params The criteria to search the users with.
	  * @return An HVZUserArray containing all members that were read.
	  */
	 public static HVZUserArray readUsers(List<NameValuePair> params)
	{
    	try
    	{    		
    		
    		// Get the raw array from the server.
    		JSONArray raw = (JSONArray) queryServer(QueryMode.READ, params);
    		HVZUserArray finalArray = new HVZUserArray(); // The converted JSONArray.
    		if(raw.getJSONObject(0).has("SUCCESS")) // if query was successful
    		{
    			// Start with the second result and add that to the HVZUserArray.
    			// NOTE: The first result is the SUCCESS message.
    			for (int i = 1; i < raw.length(); i++)
    			{
    				finalArray.put(raw.get(i));
    			}
    		}
    		return finalArray;
    	} catch (JSONException e) {
    		Log.e("Humans VS Zombies", "Error parsing JSON "+e.toString());
    	} catch (NullPointerException e) {
    		return null;
    	}
		return null;
	}

	/**
	 * Read a single user based off a barcode.
	 *
	 * @param barcode the barcode of the target user
	 * @return the user with the given barcode.
	 */
	public static HVZUser readUser(String barcode)
	{
		// Create the params containing only the barcode. This should be enough info.
		List<NameValuePair> params = new ArrayList<NameValuePair>();
		params.add(new BasicNameValuePair("barcode", barcode));
		
		// Read the users.
		HVZUserArray users = readUsers(params);
		if (users==null||users.length()!=1) // if an error or multiple users were returned
			return null;
		return users.getHVZUser(0);
	}

	/**
	 * Adds the user.
	 *
	 * @param newUser the new user
	 * @return the jSON object
	 */
	public static JSONObject addUser(HVZUser newUser)
	{
		List<NameValuePair> params = getParamsFromHVZUser(newUser);
		
		return (JSONObject) queryServer(QueryMode.ADD_USER, params);
	}

	
	/**
	 * Removes the user.
	 *
	 * @param user Must have at least one defined qualifier for
	 * for a user.
	 * @return the jSON object
	 */
	public static JSONObject removeUser(HVZUser user)
	{
		List<NameValuePair> params = getParamsFromHVZUser(user);
		
		return (JSONObject) queryServer(QueryMode.REMOVE_USER, params);
	}
	
	/**
	 * Gets the params from hvz user.
	 *
	 * @param newUser the new user
	 * @return the params from hvz user
	 */
	private static List<NameValuePair> getParamsFromHVZUser(HVZUser newUser) {
		List<NameValuePair> params = new ArrayList<NameValuePair>();
		for (Iterator<?> iterator = newUser.keys(); iterator.hasNext();) {
			String key = (String) iterator.next();
			if(key.startsWith("killcode"))
				continue;
			try {
				params.add(new BasicNameValuePair(key, newUser.getString(key)));
			} catch (JSONException e) {
				Log.e("Humans VS Zombies", e.toString());
			}
		}
		return params;
	}

	/**
	 * Kill.
	 *
	 * @param user the user
	 * @return the jSON object
	 */
	public static JSONObject kill(HVZUser user) {
		List<NameValuePair> params = getParamsFromHVZUser(user);
		
		return (JSONObject) queryServer(QueryMode.KILL, params);
	}
	
	/**
	 * Resurrect.
	 *
	 * @param user the user
	 * @return the jSON object
	 */
	public static JSONObject resurrect(HVZUser user) {
		List<NameValuePair> params = getParamsFromHVZUser(user);
		
		return (JSONObject) queryServer(QueryMode.RESURRECT, params);
	}
	
	/**
	 * Assign_killcode.
	 *
	 * @param user the user
	 * @param killcode the killcode
	 * @return the jSON object
	 */
	public static JSONObject assign_killcode(HVZUser user, String killcode) {
		List<NameValuePair> params = getParamsFromHVZUser(user);
		params.add(new BasicNameValuePair("killcode", killcode));
		
		return (JSONObject) queryServer(QueryMode.KILLCODE_ASSIGN, params);
	}
	
	/**
	 * Score_killcode.
	 *
	 * @param user the user
	 * @param killcode the killcode
	 * @return the jSON object
	 */
	public static JSONObject score_killcode(HVZUser user, String killcode) {
		List<NameValuePair> params = getParamsFromHVZUser(user);
		params.add(new BasicNameValuePair("killcode", killcode));
		
		return (JSONObject) queryServer(QueryMode.KILLCODE_ACQUIRE, params);
	}

	/**
	 * Modify user.
	 *
	 * @param user the user
	 * @return the jSON object
	 */
	public static JSONObject modifyUser(HVZUser user) {
		List<NameValuePair> params = getParamsFromHVZUser(user);
		
		return (JSONObject) queryServer(QueryMode.MODIFY_INFO, params);
	}
}
